【應試目標能力】
701.3 源碼管理 Source Code Management (5)
第二個要介紹的是源碼管理工具 Git。這個由 Linux 之父 Linus Torvalds 所發明的工具,我想大家都很熟悉了。在源碼管理工具中,Git 普遍被認為是一個進入門檻較高的工具,但隨著 GitHub、GitLab 這類以 Git 作為基礎的代碼託管平台的盛行,網路上有愈來愈多人發表各樣的教學文件或影片供大眾學習。Git 的功能十分強大,一般情況下我覺得很難掌握它的全部特性,而且有的功能可能要很久才會用到一次,因此還是先以瞭解 Git 的基本用法作為這幾天的學習目標。
在開始學習 Git 之前,應該要先對源碼管理或版本控制有一些概念。我在念書的時候不知道有版本控制工具這種東西能用,於是就把目錄或檔案名稱加上日期作為不同版本的區別,然後程式碼中也四處充斥著註解掉的程式碼。其實也不是說這樣作就一定不好,如果只有自己一個人寫程式碼,也很習慣這樣的工作模式,那不需要特別改變。以個人經驗來說,在一個人的專案中使用 Git 的好處,是知道只要有提交 (commit) 就幾乎一定可以找得回來,所以可以比較放心的去刪除修改程式。當然如果是多人一起協同開發,那麼有一套源碼管理工具就是十分必要的了。我覺得在學習 Git 時,除了知道指令怎麼用之外,還要去體會 Git 的設計,它的使用方式如何與各種協同開發工作模式相互作用。我想這也是 Git 為什麼這麼受歡迎的原因之一,因為它為團隊合作開發帶來了新的模式及可能性。
我將 Git 的學習分為三個維度,第一個維度為上下,考慮線性時間,在這個維度包括瞭解提交 (commit)、如何提交、如何回覆檔案狀態至某一個版本等基礎操作。第二個維度是左右,在原本單一線性的基礎上考慮分支,在這個維度要瞭解 branch 的用途及如何管理。第三個維度為前後,考慮與他人合作,在這個維度要瞭解遠端儲存庫 (remote repository) 的相關操作。如果只是一個人開發管理不太大的專案,其實瞭解到第一個維度也就夠用了,但如果是團隊的協同開發,那麼綜合第二個維度與第三個維度,才能發揮 Git 的真正作用。抱持這樣的想法,依照自己的需求去學習實際上會用到的功能,這樣應該會輕鬆一些。
今天打算介紹第一個維度的內容,主要的程式碼及圖片取自 Pro Git
,第二版由 Scott Chacon 和 Ben Straub 合寫,在 https://git-scm.com/book/en/v2 提供線上閱讀,部分章節亦有繁體中文翻譯。
Git 的版本控制原則上是以一個目錄為範圍,在這個目錄裡面的檔案及子目錄,我們可以隨時紀錄在某個時刻下的特定狀態,包括有那些資料、那些資料的內容等等,每一次的記錄稱為一個 commit。在這裡把 commit 翻成「提交」,也可以作動詞使用,指的是我們「告訴 Git 記錄目前狀態」的動作 。提交可以想成是 Git 會在它的資料庫中,用它的方式將目錄中的資料保留一份,這個資料庫在 Git 的術語稱作儲存庫 (repository)。
提交有先後次序之分,因此可以將其排列成一個線性的記錄。版本控制系統最主要的一個功能,就是讓我們可以查看這個線性的記錄,並允許我們讓目前的工作目錄內容,回復到任何一個先前曾被記錄的狀態。
目前 Git 已有圖形化介面的客戶端軟體,不過我們學習時還是以命令列模式的指令為主。Git 安裝方法請參考 https://git-scm.com/downloads 的說明。安裝好之後,我們要進行一些簡單的設定,最主要的是告訴 Git 你是誰。Git 的設定有範圍大小區分,從整個系統、單一使用者到專案,而告訴 Git 身份是屬於使用者範圍的設定,例如:
$ git config --global user.name "John Doe"
$ git config --global user.email johndoe@example.com
另一個常用的設定文字編輯器類型,例如:
$ git config --global core.editor vim
上述設定在提交時會用到,包含使用那種文字編輯器來編輯提交訊息,以及提交時會保留的提交者資訊。
要看目前的設定內容,可以用
$ git config --list
接下來要正式進入工具的使用。前面有提過版本控制以一個目錄為範圍,所以我們先選擇一個目錄,稱之為工作目錄 (working directory),進入該目錄後,使用
$ git init
這個指令會在此目錄中產生一個 .git
的目錄,用以存放 Git 進行版本管理時所產生的內容。如果這個目錄之後不需版控,直接將 .git
目錄刪除即可。
在這個目錄中新增一些檔案並隨意編輯其內容,現在我們要進行初次提交,Git 會幫忙記住此刻在這個目錄中有那些內容。接下來是很重要的概念 -- Git 的兩階段提交。在真正的提交之前,要先告訴 Git 有那些東西想要提交,使用的指令是
$ git add <file>
針對在工作目錄中第一次新增的檔案,這個指令告訴 Git 我們想要 Git 「納管」這個檔案,Git 就會開始追蹤這個檔案。接下來若我們更改了這個檔案的狀態(可能是修改或刪除),在提交之前,必須再使用一次 git add 指令告訴 Git 它的狀態更動了。在 Git 中這個階段叫 staging ,有點像是把檔案放入暫存區 (staging area) 的概念,在文件中有另外一種說法叫作 index,git add 就是把檔案加到 index 的意思。如果想要更新工作目錄中所有檔案的狀態,可以加上 -A
參數。
$ git add -A
在提交之前,可能會想看一下目前工作目錄的狀態,指令如下:
$ git status
以下我們借用 Pro Git
一書中的範例儲存庫,可由下述指令取得:
$ git clone https://github.com/schacon/simplegit-progit
執行完這個指令,會在當前目錄下新增 simplegit-progit
這個目錄,裡面有三個檔案。為了說明方便,我在工作目錄中作一些修改,以下為修改後執行 git status
這個指令的輸出。前兩行它會告訴我們目前所在的分支,以及和遠端儲存庫的同步狀態,之後會再介紹。我們看到下方關於檔案狀態的描述有三個段落,說明如下:
Changes to be committed
,表示這是 Git 有納管的檔案,而且在這次提交中已先使用 git add
指令告知狀態更改。deleted 表示此檔案被刪除,modified 表示檔案內容有更動,new file 表示為此次提交要新增納管的檔案。Changes not staged for commit
表示這個檔案先前已被納管,但是更動內容後並沒有再以 git add
告知我們要在這次的提交中更新其狀態。Untracked files
表示這個檔案沒有被 Git 納管。在括號內的文字說明針對這三個狀態的檔案後續可能進行的操作,包括回復先前狀態或放棄變更,之後會有更詳細的說明。
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
deleted: README
modified: Rakefile
new file: new-file.txt
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)
modified: lib/simplegit.rb
Untracked files:
(use "git add <file>..." to include in what will be committed)
no-commit.txt
要是沒問題的話就可以用下面的指令進行提交了。
$ git commit
今天先到這裡,明天針對提交再作進一步的說明。